Function.RegisterNamespace("Test");

[Import("../../Source/Extensions.js/Error.js")]
[Fixture]
Test.Error=function(){
    [Fixture]
    function Equals(){
        [Fact]
        function ThrowsIfPassedInvalidExpectedError(){
            var expected="Error.Equals: 'expected' must be a valid Error.";
            
            var actual=Record.Exception(function(){
                Error.Equals(new Object());
            });
            
            Assert.Equal(expected,actual);
        }
        [Fact]
        function ReturnsFalseIfPassedInvalidActualError(){
            var actual=Error.Equals(new Error(),new Object());
            
            Assert.False(actual);
        }
        [Fact]
        function SetsReasonIfPassedInvalidActualError(){
            var expected="Error.Equals: 'actual' was not a valid Error.";
            var reason={};
            
            Error.Equals(new Error(),new Object(),reason);
            var actual=reason.Value;
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsTrueIfNamesMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.name=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.name=expected;
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsFalseIfNamesDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.name=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.False(actual);
        }

        [Fact]
        function ReturnsTrueIfMessagesMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.message=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.message=expected;
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsFalseIfMessagesDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.message=expected;
            var actualTarget=new Error();
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.False(actual);
        }

        [Fact]
        function ReturnsTrueIfDescriptionsMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.description=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.description=expected;
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsFalseIfDescriptionsDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.description=expected;
            var actualTarget=new Error();
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.False(actual);
        }
        
        [Fact]
        function ReturnsTrueIfNumbersMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.number=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.number=expected;
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsFalseIfNumbersDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.number=expected;
            var actualTarget=new Error();
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.False(actual);
        }
        
        [Fact]
        function ReturnsTrueIfFileNamesMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.fileName=expected;
            expectedTarget.lineNumber=0;
            var actualTarget=new Error();
            actualTarget.fileName=expected;
            actualTarget.lineNumber=0;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsFalseIfFileNamesDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.fileName=expected;
            var actualTarget=new Error();
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.False(actual);
        }

        [Fact]
        function ReturnsTrueIfLineNumbersMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.lineNumber=expected;
            var actualTarget=new Error();
            actualTarget.lineNumber=expected;
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }

        [Fact]
        function ReturnsTrueIfLineNumbersDontMatch(){
            var expected="expected";
            var expectedTarget=new Error();
            expectedTarget.lineNumber=expected;
            var actualTarget=new Error();
            
            var actual=Error.Equals(expectedTarget,actualTarget);
            
            Assert.True(actual);
        }
        
        [Fact]
        function SetsValueOnReasonIfPropertiesDontMatch(){
            var targetProperty="name";
            var expectedTarget=new Error();
            expectedTarget[targetProperty]="expected";
            var actualTarget=new Error();
            actualTarget[targetProperty]="actual";
            var expected=String.Format("Error.Equals: '{0}' did not match. Expected value '{1}', found '{2}'.",targetProperty,expectedTarget[targetProperty],actualTarget[targetProperty]);
            var reason={};
            
            Error.Equals(expectedTarget,actualTarget,reason);
            var actual=reason.Value;
            
            Assert.Equal(expected,actual);
        }
    }

    [Fixture]
    function IsEmpty(){
        [Fact]
        function ThrowsIfInstanceIsNotError(){
            var expected="Error.IsEmpty: 'error' must be a valid Error.";

            var actual=Record.Exception(function(){
                Error.IsEmpty({});
            });

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsFalseIfErrorHasMessage(){
            var target=new Error();
            target.message="message";

            var actual=Error.IsEmpty(target);

            Assert.False(actual);
        }
        
        [Fact]
        function ReturnsFalseIfErrorHasDescription(){
            var target=new Error();
            target.description="description";

            var actual=Error.IsEmpty(target);

            Assert.False(actual);
        }

        [Fact]
        function ReturnsTrueIfErrorHasNoMessageOrDescription(){
            var target=new Error();

            var actual=Error.IsEmpty(target);

            Assert.True(actual);
        }
    }
    
    [Fixture]
    function toString(){
        [Fact]
        function ReturnsMessageIfSet(){
            var expected="expected";
            var target=new Error();
            target.message=expected;
            
            var actual=target.toString();
            
            Assert.Equal(expected,actual);
        }
 
        [Fact]
        function ReturnsDescriptionIfMessageNotSet(){
            var expected="expected";
            var target=new Error();
            target.description=expected;
            
            var actual=target.toString();
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsErrorCastToStringIfDescriptionNotSet(){
            var expected='';
            var target=new Error();
            
            var actual=target.toString();
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsImplementationSpecificErrorIfConstructorCalled(){
            var expected="expected";
            var target=new Error(expected);
            
            var actual=target.toString();
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsNameOfNativeTypeError(){
            var expected="TypeError";
            
            var actual=Record.Exception(function(){
                new Object().FunctionThatDoesNotExist();
            });
            
            Assert.Equal(expected,actual.name);
        }
        
        [Fixture]
        function Verbose(){
            [Fact]
            function AddsLineToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.line=7357;
                targetError.lineNumber=targetError.number=null;
                targetError.stack=targetError.stackTrace=targetError.getStack=null;
                var expected=String.Format("{0}\n\t(line: {1})",targetMessage,targetError.line);

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);
            }

            [Fact]
            function AddsLineNumberToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.lineNumber=7357;
                targetError.line=targetError.number=null;
                targetError.stack=targetError.stackTrace=targetError.getStack=null;
                var expected=String.Format("{0}\n\t(line: {1})",targetMessage,targetError.lineNumber);

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);
            }

            [Fact]
            function AddsNumberToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.number=7357;
                targetError.line=targetError.lineNumber=null;
                targetError.stack=targetError.stackTrace=targetError.getStack=null;
                var expected=String.Format("{0}\n\t(number: {1})",targetMessage,targetError.number);

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);            
            }

            [Fact]
            function AddsStackTraceToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.stackTrace=7357;
                targetError.line=targetError.lineNumber=targetError.number=null;
                targetError.stack=targetError.getStack=null;
                var expected=String.Format("{0}\n\tStackTrace: {1}",targetMessage,targetError.stackTrace);

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);            
            }

            [Fact]
            function AddsStackToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.stack=7357;
                targetError.line=targetError.lineNumber=targetError.number=null;
                targetError.stackTrace=targetError.getStack=null;
                var expected=String.Format("{0}\n\tStackTrace: {1}",targetMessage,targetError.stack);

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);
            }

            [Fact]
            function AddsGetStackResultToOutput(){
                var targetMessage="targetMessage";
                var targetError=new Error(targetMessage);
                targetError.getStack=function(){return 7357};
                targetError.line=targetError.lineNumber=targetError.number=null;
                targetError.stack=targetError.stackTrace=null;
                var expected=String.Format("{0}\n\tStackTrace: {1}",targetMessage,targetError.getStack());

                var actual=targetError.toString(true);

                Assert.Equal(expected,actual);
            }
        }        
    }   
}